package com.zkx.system.generator.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zkx.common.exception.APIException;
import com.zkx.system.generator.entity.*;
import com.zkx.system.generator.mapper.RecordMapper;
import com.zkx.system.generator.mapper.RoleMapper;
import com.zkx.system.generator.mapper.UserMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zkx.common.result.ResultCode;
import com.zkx.common.utils.JWTUtils;
import com.zkx.common.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2021-08-10
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    UserMapper userMapper;

    @Autowired
    RecordMapper recordMapper;

    @Autowired
    RedisUtil redisUtil;


    @Autowired
    RoleMapper roleMapper;

    public String insert(User user){
        //用户名或密码为"" 抛异常
        if(user.getUserName().equals("") ||user.getPassword().equals("")){
            throw new APIException(ResultCode.NOT_EMPTY);
        }
        //用户名或密码长度不符合要求 抛异常
        else if(user.getUserName().length()<3||user.getUserName().length()>11||user.getPassword().length()<6||user.getPassword().length()>11){
            throw new APIException(ResultCode.ILLEGAL_LENGTH);
        }
        //符合要求 向数据库添加新用户成功
        else{
            userMapper.insertUser(user);
            return "insert success";
        }
    }

    public String login(Integer id, String name, String password){
        User user = userMapper.selectById(id);
        //用户输入id不存在 抛异常
        if(user==null){
            throw new APIException(ResultCode.USER_NOT_EXIST);
        }
        else if(name.equals("") ||password.equals("")){
            throw new APIException(ResultCode.NOT_EMPTY);
        }
        //用户名或密码长度不符合要求 抛异常
        else if(name.length()<3||name.length()>11||password.length()<6||password.length()>11){
            throw new APIException(ResultCode.ILLEGAL_LENGTH);
        }
        else if(user.getId().equals(id) && user.getUserName().equals(name)&&user.getPassword().equals(password)){
            //往缓存中放入userId 对应的token
            //缓存中存在userId id的key 则说明此用户已经登录过
            //不给其再生成token 保证userId 对应token的唯一性
            if(redisUtil.hasKey("userId "+id)){
                throw new APIException(ResultCode.USER_ALREADY_LOGGED_IN);
            }
            else{
                Map<String,String> payload = new HashMap<>();
                payload.put("id",id.toString());
                payload.put("name",name);
                String token = StaticClass.getToken();
                //如果token不为"" 删除上一次登录保存的token 和 userId x
                if(!token.equals("")){
                    Integer userId = ((UandRandA)redisUtil.get(token)).getId();
                    redisUtil.del(token);
                    redisUtil.del("userId "+userId);
                    //如果上一位用户查询到了UandA 和 UandR 新一位用户登录时 删除上一位用户放入缓存中的UandA UandR
                    if(redisUtil.hasKey("UandA "+userId)){
                        redisUtil.del("UandA "+userId);
                    }
                    if(redisUtil.hasKey("UandR "+userId)){
                        redisUtil.del("UandR "+userId);
                    }
                }
                StaticClass.setToken(JWTUtils.getToken(payload));
                UandRandA u = setUandRandA(id,name);

                redisUtil.set(StaticClass.getToken(),u,3600);
                //放入userId number 用来防止重复登录生成不同的token
                redisUtil.set("userId "+id,null,3600);
            }
            return "login success";
        }
        else{
            throw new APIException(ResultCode.USER_LOGIN_FAIL);
        }
    }
    //删除用户的token信息和表示此用户已登录的key，更新数据库中user表中的信息
    public User update(User user,String token){
        String password = user.getPassword();
        String userName = user.getUserName();
        //用户名或密码为"" 抛异常
        if(userName.equals("") ||password.equals("")){
            throw new APIException(ResultCode.NOT_EMPTY);
        }
        //用户名或密码长度不符合要求 抛异常
        else if(userName.length()<3||userName.length()>11||password.length()<6||password.length()>11){
            throw new APIException(ResultCode.ILLEGAL_LENGTH);
        }
        //if(ifTokenExist(token)){
            UandRandA uandRandA = (UandRandA) redisUtil.get(token);
            redisUtil.del(token);
            Integer userId = uandRandA.getId();
            redisUtil.del("userId "+userId);
            user = userMapper.selectById(userId);
            user.setUserName(userName);
            user.setPassword(password);
            userMapper.updateUser(user);

            StaticClass.setToken("");

            return user;
        //}
        //redis中查找不到输入的token
//        else{
//            throw new APIException(ResultCode.TOKEN_ERROR);
//        }
    }
    //删除token和表示此用户已登录的key 和 数据库user表中的信息
    public UandRandA delete(String token){
        UandRandA uandRandA = (UandRandA) redisUtil.get(token);
        Integer userId = uandRandA.getId();
        LinkedList<Record> recordList = recordMapper.selectRecordUserId(uandRandA.getId(),0);
        //如果集合中有值，获取集合最后一个元素的值 目的为获取最后一条记录
        if(recordList.size()!=0){
            throw new APIException(ResultCode.USER_BORROWED_BOOK_NOT_RETURNED);
        }else{
            redisUtil.del(token);
            redisUtil.del("userId "+userId);
            userMapper.deleteById(userId);
            System.out.println("delete success");
            return uandRandA;
        }
    }

    public UandRandA select(String token){
        return (UandRandA)redisUtil.get(token);
    }

    public String out(String token){
        Integer userId;
        if(StaticClass.getToken().equals(token)){
            UandRandA uandRandA = (UandRandA) redisUtil.get(token);
            if(redisUtil.hasKey("userId "+uandRandA.getId())){
                userId = uandRandA.getId();
                redisUtil.del("userId "+userId);
                //如果上一位用户查询到了UandA 和 UandR 新一位用户登录时 删除上一位用户放入缓存中的UandA UandR
                if(redisUtil.hasKey("UandA "+userId)){
                    redisUtil.del("UandA "+userId);
                }
                if(redisUtil.hasKey("UandR "+userId)){
                    redisUtil.del("UandR "+userId);
                }
            }
            else{
                throw new APIException(ResultCode.ERROR);
            }
            redisUtil.del(token);
            StaticClass.setToken("");
            return "User logout succeeded";
        }
        else if(StaticClass.getToken().equals("")){
            throw new APIException(ResultCode.USER_NOT_LOGIN);
        }
        else{
            throw new APIException(ResultCode.ERROR);
        }
    }

    //查找指定页码的所有成员信息
    //pageNumber 请求的页码 number 每页的记录数
    public Page<User> selectAll(Integer pageNumber, Integer number){
        if(pageNumber<1||number<1){
            throw new APIException(ResultCode.PAGE_NUMBER_ILLEGAL);
        }
        else{
            Page<User> page = new Page<>(pageNumber,number);
            return userMapper.selectPage(page,null);
        }
    }
    public boolean ifTokenExist(String token){
        return redisUtil.hasKey(token);
    }


    //token为Key 设置value值的方法
    public UandRandA setUandRandA(Integer id,String name){
        UandRandA u = new UandRandA();
        u.setId(id);
        u.setUserName(name);
        List<String> roles = new ArrayList<>();
        List<String> accesses = new ArrayList<>();
        if(roleMapper.selectUandRByUserId(id).size()!=0){
            for (int i = 0; i < roleMapper.selectUandRByUserId(id).size(); i++) {
                roles.add(i,roleMapper.selectUandRByUserId(id).get(i).getRoleName());
            }
            u.setRoles(roles);
        }
        if(roleMapper.selectUandAByUserId(id).size()!=0){
            for (int i = 0; i < roleMapper.selectUandAByUserId(id).size(); i++) {
                accesses.add(i,roleMapper.selectUandAByUserId(id).get(i).getFunction());
            }
            u.setAccesses(accesses);
        }
        return u;
    }
}
